package com.wtp.wallpaper.utils;

import cn.hutool.core.io.FileUtil;
import com.alibaba.cloud.commons.io.FileUtils;
import com.github.junrar.exception.RarException;
import lombok.Cleanup;
import org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry;
import org.apache.commons.compress.archivers.sevenz.SevenZFile;
import org.apache.commons.compress.utils.IOUtils;
import com.github.junrar.Archive;
import com.github.junrar.rarfile.FileHeader;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class UnzipUtil {


    public static void extractArchive(MultipartFile file, String outputDir) throws Exception {
        // 保存上传文件到临时目录
        Path tempFile = Paths.get(outputDir,file.getOriginalFilename());
        PictureReduceUtil.createDir(outputDir);

        file.transferTo(tempFile);
        
        try {
            String fileName = file.getOriginalFilename().toLowerCase();
            if (fileName.endsWith(".zip")) {
                unzip(tempFile, outputDir);
            } else if (fileName.endsWith(".rar")) {
                unrar(tempFile, outputDir);
            } else if (fileName.endsWith(".7z")) {
                un7z(tempFile, outputDir);
            } else {
                throw new IllegalArgumentException("Unsupported file format");
            }
        } finally {
            // 清理临时文件
            Files.deleteIfExists(tempFile);
        }
    }

    // 解压ZIP文件
    public static void unzip(Path zipFile, String outputDir) throws IOException {
        // 使用正确的字符编码（例如 GBK）创建 ZipInputStream
        try (ZipInputStream zis = new ZipInputStream(Files.newInputStream(zipFile), Charset.forName("GBK"))) {
            ZipEntry entry;
            while ((entry = zis.getNextEntry()) != null) {
                // 使用 entry.getName() 前确保编码正确
                Path outputPath = safeResolve(outputDir, entry.getName());
                // 后续处理保持不变...
                if (entry.isDirectory()) {
                    Files.createDirectories(outputPath);
                } else {
                    Files.createDirectories(outputPath.getParent());
                    try (OutputStream fos = Files.newOutputStream(outputPath)) {
                        IOUtils.copy(zis, fos);
                    }
                }
            }
        }
    }


    /**
     * 解压RAR文件到指定目录（支持RAR5需要确认库版本）
     *
     * @param srcRarPath       源RAR文件路径
     * @param dstDirectoryPath 目标解压目录
     * @return 解压目录路径
     * @throws IOException 文件操作异常
     */
    public static String unrar(Path srcRarPath, String dstDirectoryPath) throws IOException {
        Path destDir = Paths.get(dstDirectoryPath).toAbsolutePath().normalize();
        Files.createDirectories(destDir);

        try (InputStream is = Files.newInputStream(srcRarPath);
             Archive archive = new Archive(is)) {

            FileHeader fileHeader;
            while ((fileHeader = archive.nextFileHeader()) != null) {
                processFileHeader(archive, fileHeader, destDir);
            }
        } catch (Exception e) {
            throw new IOException("解压RAR文件失败", e);
        }
        return destDir.toString();
    }

    private static void processFileHeader(Archive archive, FileHeader fileHeader, Path destDir) throws IOException {
        String fileName = getValidFileName(fileHeader);
        Path targetPath = destDir.resolve(fileName).normalize();

        validateSafeExtraction(destDir, targetPath);

        if (fileHeader.isDirectory()) {
            Files.createDirectories(targetPath);
        } else {
            extractFile(archive, fileHeader, targetPath);
        }
    }

    private static String getValidFileName(FileHeader fileHeader) {
        String fileName = !fileHeader.getFileNameW().isEmpty() ?
                fileHeader.getFileNameW() :
                fileHeader.getFileNameString();
        return fileName.replace('\\', '/')  // 统一路径分隔符
                .replace("..", "")   // 简单防护路径遍历
                .trim();
    }

    private static void validateSafeExtraction(Path destDir, Path targetPath) throws IOException {
        if (!targetPath.startsWith(destDir)) {
            throw new IOException("检测到非法路径遍历: " + targetPath);
        }
    }

    private static void extractFile(Archive archive, FileHeader fileHeader, Path targetPath) throws IOException {
        Files.createDirectories(targetPath.getParent());

        try (OutputStream os = Files.newOutputStream(targetPath,
                StandardOpenOption.CREATE,
                StandardOpenOption.TRUNCATE_EXISTING)) {
            archive.extractFile(fileHeader, os);
        } catch (RarException e) {
            throw new RuntimeException(e);
        }
    }


    // 解压7Z文件
    public static void un7z(Path sevenZFile, String outputDir) throws IOException {
        try (SevenZFile sevenZ = new SevenZFile(sevenZFile.toFile())) {
            SevenZArchiveEntry entry;
            while ((entry = sevenZ.getNextEntry()) != null) {
                if (entry.isDirectory()) continue;
                
                Path outputPath = safeResolve(outputDir, entry.getName());
                Files.createDirectories(outputPath.getParent());
                try (OutputStream os = Files.newOutputStream(outputPath)) {
                    byte[] content = new byte[(int) entry.getSize()];
                    sevenZ.read(content, 0, content.length);
                    os.write(content);
                }
            }
        }
    }

    // 安全路径解析，防止路径遍历攻击
    private static Path safeResolve(String outputDir, String entryName) throws IOException {
        Path targetDir = Paths.get(outputDir).toAbsolutePath().normalize();
        Path entryPath = targetDir.resolve(entryName).normalize();
        
        if (!entryPath.startsWith(targetDir)) {
            throw new IOException("Invalid entry: " + entryName);
        }
        return entryPath;
    }
}